var hex2json = (function() {
    var typeList = // 类型列表：空格 a字母 0数字 { } : , " +
        '"0 +{}:,"+a{}:,"';
    var stateMap = { // 状态表：{ 当前状态: 有效后续 }
        '*': [ // 等待新项
            '   ', // 后续类型 后续状态（空表示不变） 输出格式（无表示取原字符）
            'ak',
            '}-}',
            '"+"',
        ],
        'k': [ // 等待键名
            'a',
            '}-}',
            ':.:',
            ',*,',
        ],
        ':': [ // 等待冒号
            '   ',
            ':.:',
        ],
        '.': [ // 等待键值
            '   ',
            'av',
            '00',
            '{+{',
            '"+"',
        ],
        'v': [ // 等待键值变量名
            'a',
            // '0',
            '}-}',
            ',*,',
            '+.+',
        ],
        '0': [ // 等待键值数值
            '0',
            '}-}',
            ',*,',
            '+.+',
        ],
        ',': [ // 等待逗号
            '   ',
            '}-}',
            ',*,',
            '+.+',
        ],
        '"': [ // 等待字符串
            ' ',
            'a',
            '0',
            '{',
            '}',
            ':',
            ',',
            '"-"',
            '+',
        ],
    };
    var stateCompact = {
        'k': [ // 兼容IE时键名不能单独用
            'a',
            ':.:',
        ],
    };
    var stateMapUse;
    var state;
    var stack;

    // 交换字符
    function swap(c) {
        var g = 'charAt';
        var index = parseInt(c, 16);
        var type = typeList[g](index);
        var nextList = stateMapUse[state] || stateMap[state];
        for (var i in nextList) {
            var item = nextList[i];
            if (item[g](0) == type) {
                return next(item[g](1), item[g](2) || c);
            }
        }
        var item = nextList[index % nextList.length];
        return next(item[g](1), item[g](2) || (item[g](0) == '0' ? '0' : 'a'));
    }

    // 进入下一状态
    function next(nextState, output) {
        // document.write(output + state + nextState);
        if (nextState == '+') { // 进入嵌套
            stack.push(state);
            state = output == '"' ? '"' : '*';
        } else if (nextState == '-') { // 跳出嵌套
            if (stack.length > 0) {
                state = stack.pop();
                state = state == '*' ? ':' : ',';
            } else if (state == '*') { // 层次不足改用键名（等待新项）或逗号（其他）
                state = 'k';
                output = 'a';
            } else {
                state = '*';
                output = ',';
            }
        } else if (nextState && nextState != ' ') {
            state = nextState;
        }
        // document.write(state + output + ' | ');
        return output;
    }

    // 结尾闭合处理
    function enclose(compact) {
        var more = '';
        if (state == ':') {
            more = ':a';
        } else if (state == '.') {
            more = 'a';
        } else if (state == '"') {
            more = stack.pop() == '*' ? '":a' : '"';
        } else if (compact && state == 'k') { // 兼容IE时键名不能单独用
            more = ':a';
        }
        for (var i = stack.length; i > 0; i--) {
            more += '}';
        }
        return more;
    }

    // Hex转Json
    // - @compact: 是否兼容IE
    return function(hex, compact) {
        stateMapUse = compact ? stateCompact : stateMap;
        state = '*';
        stack = [];
        return '{' + hex.replace(/./g, swap) + enclose(compact) + '}';
    };
})();
